package com.stack.knowyoubase.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.Arrays;

/**
 * 事务超时回滚切面
 * @author  ldy
 */
@Slf4j
@Component
@Aspect
public class TimeOutAspect {

    /**
     * 超时属性，时间为 4000 毫秒
     */
    @Value("4000")
    private long time;

   @Pointcut("@annotation(com.stack.knowyoubase.anotional.TimeOut)")
   public void pointCut(){
   }

   @Around("pointCut()")
   public Object around(ProceedingJoinPoint proceedingJoinPoint) throws  Throwable{
       Signature signature = proceedingJoinPoint.getSignature();
       //获取执行的类名
       String serviceName=proceedingJoinPoint.getTarget().getClass().getSimpleName();
       //获取执行的方法名
       String methodName = signature.getName();
       // 获取执行入参
       String args = Arrays.toString(proceedingJoinPoint.getArgs());
       long startTime=System.currentTimeMillis();
       long endTime = 0;
       Object result=null;
       try {
           log.info("<{}.{}>开始调用,请求参数:{}",serviceName,methodName,args);
           result = proceedingJoinPoint.proceed();
           endTime=System.currentTimeMillis();
       }catch (Throwable e){
           // 抛出异常，事务注解控制事务回滚
           log.info("<{}.{}>,执行产生异常:{}",serviceName,methodName,e.toString());
           throw e;
       }finally {
           if(time>=(endTime-startTime)){
               // 执行成功
               log.info("<{}.{}>,返回结果:{}",serviceName,methodName,result.toString());
               return result;
           }else {
               // 方法超时，手动事务回滚
               log.info("<{}.{}>,执行超时,耗时:{}毫秒,返回结果: null",serviceName,methodName,(endTime-startTime));
               TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
               return null;
           }
       }
   }

}
